package org.amuthu.expression.binary;

import org.amuthu.expression.Expression;
import org.amuthu.expression.exception.TypeMismatchException;
import org.amuthu.parser.ExpressionVisitor;

/**
 * Abstract base class for the arithmetic expressions:
 * <code>+, /, *, -</code>
 */
public class ArithmeticExpression extends BinaryExpression
{
   private ArithmeticExprType exprType;

   public ArithmeticExprType getExprType()
   {
      return exprType;
   }
   /**
    * Create a new arithmetic expression with the given left and
    * right arguments.
    */
   public ArithmeticExpression(ArithmeticExprType exprType, Expression left, Expression right)
   {
      super(left, right);
      this.exprType = exprType;
   }

   /**
    * Check the input arguments to the expression. They can only be
    * {@link #INTEGER_TYPE} or {@link #FLOAT_TYPE}.
    *     * There are 4 possible cases:
    * {@link #INTEGER_TYPE} operator {@link #INTEGER_TYPE} returns a {@link #INTEGER_TYPE}
    * {@link #INTEGER_TYPE} operator {@link #FLOAT_TYPE} returns a {@link #INTEGER_TYPE}
    * {@link #FLOAT_TYPE} operator {@link #INTEGER_TYPE} returns a {@link #FLOAT_TYPE}
    * {@link #FLOAT_TYPE} operator {@link #FLOAT_TYPE} returns a {@link #FLOAT_TYPE}
    *
    * @return	the type of the expression
    */
   @Override
   public int checkType() throws TypeMismatchException
   {
      // Types must be integer or float and not boolean or quote.
      int leftType = getChild(0).checkType();
      int rightType = getChild(1).checkType();

      if ((leftType == FLOAT_TYPE || leftType == INTEGER_TYPE)
          && (rightType == FLOAT_TYPE || rightType == INTEGER_TYPE))
      {
         return getType();
      }
      else
      {
         String types = leftType + " , " + rightType;
         String expectedTypes = FLOAT_TYPE + " , " + FLOAT_TYPE;
         throw new TypeMismatchException(this, types, expectedTypes);
      }
   }

   /**
    * Get the type of the expression.
    *
    * @return either {@link #FLOAT_TYPE} or {@link #INTEGER_TYPE}.
    */
   @Override
   public int getType()
   {
      int type = -1;

      for (int i = 0; i < getChildCount(); i++)
      {
         if (getChild(i) != null)
         {
            type = getChild(i).getType();
         }
         if (type == Expression.FLOAT_TYPE)
         {
            return type;
         }
      }
      return type;
   }

   @Override
   public void accept(ExpressionVisitor visitor)
   {
      visitor.visit(this);
   }

   @Override
   public String toString()
   {
      switch (exprType)
      {
         case ADD:
            return super.toString(" + ");
         case SUBTRACT:
            return super.toString(" - ");
         case MULTIPLY:
            return super.toString(" * ");
         case DIVIDE:
            return super.toString(" / ");
         case MODULO:
            return super.toString(" % ");
         case POWER:
            return super.toString(" ^ ");
         default:
            throw new AssertionError();
      }
   }

}
